package com.zwh.se.collection.set;




import com.zwh.se.collection.comparable_comparator.Student;
import com.zwh.se.collection.comparable_comparator.User;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author yexi
 * <p>
 * TreeSet是底层使用红黑树来实现的Set集合。TreeSet做范围查询效率高。
 * TreeSet会对存储的元素对象默认使用自然排序(从小到大)从而达到一定的有序。
 * 什么是自然排序:数字按数字大小排序、字符则按 Unicode值数字大小排序。
 * 特点：唯一、无序(无法按照输入顺序进行输出)、有序(按照元素的比较规则自然排序排好了)
 * <p>
 * 那么如果是对象呢?对象怎么自然排序?用地址吗?抱歉,如果对象不实现比较器的话,那么它会直接报错。
 * 那么什么是比较器?这点可以先去另外一处先行了解后再回来看下面的demo
 * @see com.zwh.se.collection.comparable_comparator
 * TIPS:由于集合只能存储对象,所以本质上所谓的实现自然排序是因为大部分比较器就是按照升序设计的。
 * TIPS:跟HashSet一样,TreeSet的底层是基于TreeMap来实现的。由于实现原理都类似,所以不再重复说。
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        System.out.println("--------------------[1]新增操作--------------------");
        treeSet.add(5);
        treeSet.add(1);
        treeSet.add(2);
        treeSet.add(3);
        treeSet.add(4);
        System.out.println(treeSet.add(3));//同样的元素是唯一的,false
        System.out.println(treeSet.toString());

        System.out.println("--------------------[2]查询操作--------------------");
        //boolean isEmpty(); 判断 set 是不是空的,是空的返回true
        System.out.println(treeSet.isEmpty()); //false
        //boolean contains(Object o); 如果 set 中包含指定的元素，则返回 true。
        System.out.println(treeSet.contains(3)); //true

        System.out.println("--------------------[3]移除操作--------------------");
        //boolean remove(Object o); 判断是否移除成功
        treeSet.remove(3);
        System.out.println(treeSet);
        //hashSet.clear();清空 hashSet 内的所有元素,就不演示了

        System.out.println("--------------------[4]遍历操作--------------------");
        //不存在索引,没法使用普通的for循环

        //使用for-each遍历
        for (Object ele : treeSet) {
            System.out.print(ele + " ");
        }
        System.out.println();

        //使用迭代器来遍历(国内用得比较多)
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()) {
            Object item = iterator.next();
            System.out.print(item + " ");
        }
        System.out.println();

        //对迭代器的优化(国外用得比较多)
        for (Iterator iterator2 = treeSet.iterator(); iterator2.hasNext(); ) {
            Object item = iterator2.next();
            System.out.print(item + " ");
        }

        System.out.println("--------------------[5]TreeSet结合比较器的使用--------------------");
        //该Student是已经实现了内部比较器的实体类
        Set<Student> studentSet = new TreeSet<>();
        studentSet.add(new Student("stef", 28));
        studentSet.add(new Student("will", 17));
        studentSet.add(new Student("allen", 15));
        studentSet.add(new Student("Lucy", 22));
        System.out.println(studentSet);

        //该User类是已经实现了外部比较器的实体类
        Set<User> userSet1 = new TreeSet<>(new User.AgeComparator());
        userSet1.add(new User("James", 30));
        userSet1.add(new User("Bryant", 22));
        userSet1.add(new User("Allen", 17));
        userSet1.add(new User("Will", 17));
        //WARN:虽然比较器说得比较好听,但是对于TreeSet而言,其只是通过比较器的规则来判别一个对象的唯一性再通过底层红黑树进行排序而无视了对象的其他属性罢了
        //     这就造成了一个问题。那就是当比较的值存在重复时,它会认为你存入的是同一个对象,并借此过滤掉了(此输出中可以看出元素丢失了)。
        //     所以,如果你不能保证你的比较器能做到绝对存在差异,亦或者认为丢失部分数据无所谓的话,慎用。
        System.out.println(userSet1);
        Set<User> userSet2 = new TreeSet<>(new User.NameLengthWithAgeComparator());
        userSet2.add(new User("James", 30));
        userSet2.add(new User("Bryant", 22));
        userSet2.add(new User("Allen", 28));
        userSet2.add(new User("Will", 17));
        System.out.println(userSet2);

        //证明一下TreeSet绝对没法排序没有比较器的类
        TreeSet<Object> objects = new TreeSet<>();
        try {
            objects.add(new Object());
        } catch (ClassCastException e) {
            e.printStackTrace();
        }

        /*
            TreeSet是如何获得升序的结果的：
            二叉树的遍历：
            中序遍历：左 根 右 --> TressSet使用的遍历方式
            先序遍历：根 左 右
            后序遍历：左 右 根
         */

    }
}
